home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 3 / Info_Mac_1994-01.iso / Development / Source / JPEG Convert 1.0 Source / JPEG Convert2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-10  |  40.0 KB  |  1,499 lines  |  [TEXT/KAHL]

  1. /*
  2.  * JPEG Convert2.c
  3.  *
  4.  * Copyright (C) 1992, James H. Brunner.
  5.  *
  6.  * This file is part of the "JPEG Convert" program.  The JPEG Convert program signature ('Ijgp')
  7.  * and unique file types ('TARG', 'RLE ', 'PPM ') are registered with Apple by the author.
  8.  *
  9.  * The JPEG Convert program is an image format conversion program that utilizes the software of
  10.  * the Independent JPEG Group.  The JPEG Convert program is essentially a Macintosh user interface
  11.  * around the Independent JPEG Group's code.  The author of JPEG Convert maintains a copyright to
  12.  * the interface software only.  For conditions of distribution and use of the Independent JPEG
  13.  * Group's software, refer to the README file contained in the Independent JPEG Group's distribution
  14.  * package.
  15.  *
  16.  * (Further use of the word 'software' refers only to the source files for implementing this user
  17.  *  interface, including the resource file which does not include this comment. It does NOT refer
  18.  *  to the Independent JPEG Group's code.)
  19.  *
  20.  * The conditions for distribution of this software are as follows:
  21.  *        This software may be freely distributed provided that it is not distributed for profit; a
  22.  *        nominal copying fee may be charged.
  23.  *
  24.  *        Any distribution of this software must contain all original copyright notices.
  25.  *
  26.  * The conditions for use of this software IN FULL are as follows:
  27.  *        This software may be used in full by any person or business provided that the person or
  28.  *        business is not seeking profits directly from the use of this software.
  29.  *
  30.  * The conditions for use of this software IN PART are as follows:
  31.  *        Any person or business may copy and utilize portions of this software in other products
  32.  *        provided that a note that "portions of the software are copyright by James H. Brunner"
  33.  *        is included in the software AND the resultant software is not intended to be distributed
  34.  *        for profit.
  35.  *
  36.  *        If SOURCE for projects containing portions of this code is not to be made available
  37.  *        with the resultant programs, an additional note that "portions of the software are 
  38.  *        copyright James H. Brunner" must be included in some visable user documentation.
  39.  *
  40.  * Bottom line:  I give it away free; I don't want you selling it.  You can use the source if
  41.  * you wish, but don't sell it.  If you use my work, give me credit for it.
  42.  */
  43.  
  44. /*
  45.  * JPEG Convert2.c
  46.  *
  47.  * This is part 2 of the Macintosh GUI (Graphical User Interface).  It is intended to be
  48.  * compiled on a Macintosh computer with Think C.  This section contains all of the code for
  49.  * dealing with the fancy dialogs.  All of the real program logic is in "JPEG Convert1.c"
  50.  */
  51.  
  52. #include "JPEG Convert.h"
  53.  
  54. #include <Scrap.h>
  55. #include <Packages.h>
  56. #include <Folders.h>
  57.  
  58. #define DJPEG_DLOG_ID    151
  59. #define CJPEG_DLOG_ID    150
  60. #define PREFS_DLOG_ID    250
  61.  
  62. /* item IDs in the PREFs dialog (ok and cancel are predefined) */
  63. enum {
  64.         kPdefault = 3,
  65.         kPjpegT,
  66.         kPjpegC,
  67.         kPgifT,
  68.         kPgifC,
  69.         kPppmT,
  70.         kPppmC,
  71.         kPtargaT,
  72.         kPtargaC,
  73.         kPrleT,
  74.         kPrleC,
  75.         kPoverwrite,
  76.         kPalltypes,
  77.         kPok_border = 24
  78.     };
  79.  
  80. static Handle    gHandleSink;        /* a write only "sink" for handles */
  81.  
  82. extern Boolean    gNewDialogMgr;        /* EXTERN: TRUE if the system 7 dialog manager is available */
  83. extern Boolean    gAppleEvents;        /* EXTERN: TRUE if the system 7 apple event facility is available */
  84.  
  85. extern PrefHandle    gPrefs;            /* EXTERN: User prefs from preference file and/or dialog */
  86.  
  87. #define PAD(s, c, l)    while (s[0] < l) s[++s[0]] = c
  88. #define OSTYPE_TO_STR(ostype, str)    do {sprintf((CSTR)str, "%.4s", &ostype); CtoPstr((CSTR)str);} while (0)
  89. #define STR_TO_OSTYPE(str, ostype)    do {PtoCstr((PSTR)str); sscanf((CSTR)str, "%4c", &ostype); CtoPstr((CSTR)str);} while (0)
  90.  
  91. /*
  92.  *    Using the name "inname", change the extension (or add it) as appropriate for the given
  93.  *    output format.  (ie.  if format = FMT_GIF changes infile.jpg to infile.gif)  This routine
  94.  *    allows the "inname" to be a full pathname (with ':'s for directory) and will leave the
  95.  *    pathname intact in the "outname".
  96.  */
  97. GLOBAL void
  98. fix_name (Str255 outname, Str255 inname, int format)
  99. {
  100.     int        i;
  101.     int        dot;
  102.     char    suffix[6];
  103.     char    *suffixp=suffix;
  104.     
  105.     switch (format) {
  106.         case FMT_GIF:
  107.             strcpy(suffix, "gif");
  108.             break;
  109.         case FMT_PPM:
  110.             strcpy(suffix, "ppm");
  111.             break;
  112.         case FMT_RLE:
  113.             strcpy(suffix, "rle");
  114.             break;
  115.         case FMT_TARGA:
  116.             strcpy(suffix, "targa");
  117.             break;
  118.         case FMT_JPEG:
  119.             strcpy(suffix, "jpg");
  120.             break;
  121.         default:
  122.             outname[0] = 0;
  123.             return;
  124.     }
  125.  
  126.     BlockMove(inname, outname, inname[0]+1);
  127.         
  128.     for (dot=0, i=outname[0];  i > 0;  i--) {
  129.         if (outname[i] == '.') {
  130.             dot = i;
  131.             break;
  132.         }
  133.         if (outname[i] == ':')
  134.             break;
  135.     }
  136.             
  137.     if (dot == 0)
  138.         outname[++outname[0]] = '.';
  139.     else
  140.         outname[0] = dot;
  141.     
  142.     while (*suffixp)
  143.         outname[++outname[0]] = *suffixp++;
  144. }
  145.  
  146.  
  147. /*
  148.  *    This routine converts a string to a number.  It returns false if the string does not
  149.  *    represent a valid positive integer (0-32767).
  150.  */
  151. LOCAL Boolean
  152. myStringToNum (s, i)
  153.     Str255    s;
  154.     short    *i;
  155. {
  156.     long    num;
  157.     int        x;
  158.  
  159.     for (x=1;  x <= s[0];  x++)
  160.         if (s[x] < '0'  ||  s[x] > '9')
  161.             return FALSE;
  162.             
  163.     StringToNum(s, &num);
  164.     if (num < 0  ||  num > 32767)
  165.         return FALSE;
  166.         
  167.     *i = (short)num;
  168.     
  169.     return TRUE;
  170. }
  171.  
  172.  
  173. /*
  174.  *    This is a shortcut for dealing with items in a dialog.  All of the item routines need a
  175.  *    control handle.  We have a DialogPtr and an item number.
  176.  */
  177. GLOBAL Handle
  178. ditemh (DialogPtr theDialog, short item)
  179. {
  180.     short    itemt;
  181.     Handle    itemh;
  182.     Rect    itemr;
  183.     
  184.     GetDItem(theDialog, item, &itemt, &itemh, &itemr);
  185.     return itemh;
  186. }
  187.  
  188.  
  189. /*
  190.  *    This routine is used to enable an item in a dialog box.
  191.  */
  192. LOCAL void
  193. enableItem (theDialog, item)
  194.     DialogPtr    theDialog;
  195.     short        item;
  196. {
  197.     short    kind;
  198.     Handle    itemh;
  199.     Rect    itemr;
  200.     
  201.     GetDItem(theDialog, item, &kind, &itemh, &itemr);
  202.     SetDItem(theDialog, item, kind & ~(short)itemDisable, itemh, &itemr);
  203. }
  204.  
  205.  
  206. /*
  207.  *    This routine is used to disable an item in a dialog box.
  208.  */
  209. LOCAL void
  210. disableItem (theDialog, item)
  211.     DialogPtr    theDialog;
  212.     short        item;
  213. {
  214.     short    kind;
  215.     Handle    itemh;
  216.     Rect    itemr;
  217.     
  218.     GetDItem(theDialog, item, &kind, &itemh, &itemr);
  219.     SetDItem(theDialog, item, kind | (short)itemDisable, itemh, &itemr);
  220. }
  221.  
  222.  
  223. /* This routine dims AND disables a CONTROL item in a dialog box.
  224.  */
  225. LOCAL void
  226. dimItem (theDialog, item)
  227.     DialogPtr    theDialog;
  228.     short        item;
  229. {
  230.     short    kind;
  231.     Handle    itemh;
  232.     Rect    itemr;
  233.     
  234.     GetDItem(theDialog, item, &kind, &itemh, &itemr);
  235.     SetDItem(theDialog, item, kind | (short)itemDisable, itemh, &itemr);
  236.     if (kind & ctrlItem)
  237.         HiliteControl((ControlHandle)itemh, 255);
  238. }
  239.  
  240.  
  241. /* This routine UNdims AND enables a CONTROL item in a dialog box.
  242.  */
  243. LOCAL void
  244. undimItem (theDialog, item)
  245.     DialogPtr    theDialog;
  246.     short        item;
  247. {
  248.     short    kind;
  249.     Handle    itemh;
  250.     Rect    itemr;
  251.     
  252.     GetDItem(theDialog, item, &kind, &itemh, &itemr);
  253.     SetDItem(theDialog, item, kind & ~(short)itemDisable, itemh, &itemr);
  254.     if (kind & ctrlItem)
  255.         HiliteControl((ControlHandle)itemh, 0);
  256. }
  257.  
  258.  
  259. /* This routine returns the number of characters in the selection range of the
  260.  * current textEdit item in a dialog box.  (Zero if there is a selection point.)
  261.  */
  262. LOCAL short
  263. HasSelectionRange (DialogPeek d)
  264. {
  265.     return ((*(d->textH))->selEnd - (*(d->textH))->selStart);
  266. }
  267.  
  268.  
  269. /* Given a character and the state of the command key, this routine determines if
  270.  * the key is used for editing of an editText item.
  271.  */
  272. LOCAL Boolean
  273. IsEditKey (char theKey, Boolean command)
  274. {
  275.     switch (theKey) {
  276.         case 0x1C:    /* LEFT */
  277.         case 0x1D:    /* RIGHT */
  278.         case 0x1E:    /* UP */
  279.         case 0x1F:    /* DOWN */
  280.         case 0x08:    /* BACKSPACE */
  281.         case 0x7F:    /* DELETE */
  282.         case '\t':
  283.             return TRUE;
  284.             break;
  285.             
  286.         case 'X':
  287.         case 'x':
  288.         case 'C':
  289.         case 'c':
  290.         case 'V':
  291.         case 'v':
  292.             return command;
  293.             break;
  294.             
  295.         default:
  296.             return FALSE;
  297.     }
  298. }
  299.  
  300.  
  301. /* This routine is a NOP routine used for the OK button hiliting routine IF the 
  302.  * new dialog manager routines are in use.
  303.  */
  304. GLOBAL pascal void
  305. NOPRoutine (WindowPtr dwind, short dinum)
  306. {
  307. }
  308.  
  309.  
  310. /* This routine defines a dialog item that borders the OK button.  This is only
  311.  * necessary if the OLD dialog manager is in use.
  312.  */
  313. GLOBAL pascal void
  314. BorderDefault (WindowPtr dwind, short dinum)
  315. {
  316.     short    itemType;
  317.     Rect    borderRect;
  318.  
  319.     GetDItem(dwind, ok, &itemType, &gHandleSink, &borderRect);
  320.     InsetRect(&borderRect, -4, -4);
  321.     PenSize(3, 3);
  322.     FrameRoundRect(&borderRect, 16, 16);
  323.     PenSize(1, 1);
  324. }
  325.  
  326.  
  327. /* This routine defines a dialogItem that will "dim" the text in the DJ_Q_COLORS
  328.  * editText item.  We will do this if QUANTIZE is not checked.
  329.  */
  330. METHODDEF pascal void
  331. DimColors (WindowPtr dwind, short dinum)
  332. {
  333.     if (!GetCtlValue(CITEMH(dwind, DJ_QUANTIZE))) {
  334.         PenState    thePen;
  335.         short        itemType;
  336.         Rect        dimRect;
  337.         
  338.         GetPenState(&thePen);
  339.         GetDItem(dwind, dinum, &itemType, &gHandleSink, &dimRect);
  340.         PenMode(notPatBic);
  341.         PenPat(gray);
  342.         PaintRect(&dimRect);
  343.         SetPenState(&thePen);
  344.     }
  345. }
  346.  
  347.  
  348. /* Handle this return, enter, escape stuff for both versions of the dialog manager.  This
  349.  * routine returns TRUE if we should immediately return TRUE from the dialog filter.
  350.  */
  351. GLOBAL Boolean
  352. ReturnEnterEscape (DialogPtr d, EventRecord *theEvent, short *item)
  353. {
  354.     char    theKey;
  355.     Boolean    command;
  356.     Boolean useStdFilter=FALSE;
  357.     long    ticks;
  358.  
  359.     switch (theEvent->what) {
  360.         case keyDown:
  361.         case autoKey:
  362.             theKey = theEvent->message & charCodeMask;
  363.             command = ((theEvent->modifiers & cmdKey) != 0);
  364.             
  365.             if (!command)
  366.                 switch (theKey) {
  367.                     /* If we are using the OLD dialog manager, we need to handle RETURN, ENTER,
  368.                      * and ESC.  These need to be mapped to the OK and CANCEL buttons.
  369.                      */
  370.                     case '\r':    /* RETURN */
  371.                     case 0x03:    /* ENTER */
  372.                         if (!gNewDialogMgr) {
  373.                             *item = ok;
  374.                             HiliteControl(CITEMH(d, ok), 1);
  375.                             Delay(8, &ticks);
  376.                             HiliteControl(CITEMH(d, ok), 0);
  377.                             return TRUE;
  378.                         } else
  379.                             useStdFilter = TRUE;
  380.                         break;
  381.                     case 0x1B:    /* ESC */
  382.                         if (!gNewDialogMgr) {
  383.                             *item = J_CAN;
  384.                             HiliteControl(CITEMH(d, J_CAN), 1);
  385.                             Delay(8, &ticks);
  386.                             HiliteControl(CITEMH(d, J_CAN), 0);
  387.                             return TRUE;
  388.                         } else
  389.                             useStdFilter = TRUE;
  390.                         break;
  391.                 }
  392.     }
  393.  
  394.     if (useStdFilter) {
  395.         ModalFilterProcPtr    theModalProc;
  396.                 
  397.         if (GetStdFilterProc(&theModalProc) == noErr)
  398.             return theModalProc(d, theEvent, item);
  399.     }
  400.  
  401.     return FALSE;
  402. }
  403.  
  404.  
  405. /* This is a dialog filter for the DJPEG dialog.  A lot of nifty stuff is done here!
  406.  */
  407. METHODDEF pascal Boolean
  408. djpeg_dialog_filter (DialogPtr d, EventRecord *theEvent, short *item)
  409. {
  410.  
  411.     short    itemType;
  412.     Handle    itemHandle;
  413.     Rect    itemRect;
  414.     Point    mouseLoc;
  415.     char    theKey;
  416.     Boolean    command;
  417.     Boolean    alreadyHandled=FALSE;
  418.     
  419.     SetPort(d);
  420.  
  421.     /* We need to manage the IBeam cursor for DJPEG (OLD and NEW dialog managers) because
  422.      * we don't want an IBeam over an inactive editText item.
  423.      */
  424.     GetMouse(&mouseLoc);
  425.     GetDItem(d, DJ_Q_COLORS, &itemType, &gHandleSink, &itemRect);
  426.     if (PtInRect(mouseLoc, &itemRect))
  427.         if (!GetCtlValue(CITEMH(d, DJ_QUANTIZE)))
  428.             SetCursor(&arrow);
  429.         else
  430.             SetCursor(*GetCursor(1));
  431.     else {
  432.         GetDItem(d, DJ_DEBUG, &itemType, &gHandleSink, &itemRect);
  433.         if (PtInRect(mouseLoc, &itemRect))
  434.             SetCursor(*GetCursor(1));
  435.         else
  436.             SetCursor(&arrow);
  437.     }
  438.  
  439.     if (ReturnEnterEscape(d, theEvent, item))
  440.         return TRUE;
  441.     
  442.     switch (theEvent->what) {
  443.         case keyDown:
  444.         case autoKey:
  445.             theKey = theEvent->message & charCodeMask;
  446.             command = ((theEvent->modifiers & cmdKey) != 0);
  447.             
  448.             if (!command)
  449.                 switch (theKey) {
  450.                     /* New or old dialog manger, we need to handle TAB because of our funky inactive 
  451.                      * editText item.  If the item is inactive, me must tab over the item instead of
  452.                      * into it.
  453.                      */
  454.                     case '\t':
  455.                         switch (((DialogPeek)d)->editField + 1) {
  456.                             case DJ_Q_COLORS:
  457.                                 SelIText(d, DJ_DEBUG, 0, MAXINT);
  458.                                 break;
  459.                             case DJ_DEBUG:
  460.                                 if (GetCtlValue(CITEMH(d, DJ_QUANTIZE)))
  461.                                     SelIText(d, DJ_Q_COLORS, 0, MAXINT);
  462.                                 else
  463.                                     SelIText(d, DJ_DEBUG, 0, MAXINT);
  464.                                 break;
  465.                         }
  466.                         alreadyHandled = TRUE;
  467.                         break;
  468.                 }
  469.             
  470.             if (!alreadyHandled) {
  471.                 if (!command  &&  !IsEditKey(theKey, command))
  472.                     switch (((DialogPeek)d)->editField+1) {
  473.                         /* We only want numbers in COLORS and DEBUG, so map out the rest. */
  474.                         case DJ_Q_COLORS:
  475.                         case DJ_DEBUG:
  476.                             if ((theKey < '0') || (theKey > '9')) {
  477.                                 SysBeep(1);
  478.                                 alreadyHandled = TRUE;
  479.                             }
  480.                             break;
  481.                     }
  482.  
  483.                 /* Make sure that the maximum field lengths are not exceeded! */
  484.                 if (!alreadyHandled) {
  485.                     short    max_chars;
  486.                     short    selection;
  487.                     long    scraplen;
  488.                     long    offset;
  489.                     Str63    theText;
  490.                     
  491.                     switch (((DialogPeek)d)->editField+1) {
  492.                         case DJ_Q_COLORS:
  493.                             max_chars = 3;
  494.                             break;
  495.                         case DJ_DEBUG:
  496.                             max_chars = 1;
  497.                             break;
  498.                     }
  499.  
  500.                     selection = HasSelectionRange((DialogPeek)d);
  501.                     
  502.                     GetIText(ditemh(d, ((DialogPeek)d)->editField+1), theText);
  503.                     
  504.                     if (IsEditKey(theKey, command)) {
  505.                         if ((theKey == 'V') || (theKey == 'v')) {
  506.                             scraplen = GetScrap(NULL, 'TEXT', &offset);
  507.                             if (theText[0] + scraplen - selection > max_chars) {
  508.                                 SysBeep(1);
  509.                                 alreadyHandled = TRUE;
  510.                             }
  511.                         }
  512.                     } else {
  513.                         if (theText[0] + 1 - selection > max_chars) {
  514.                             SysBeep(1);
  515.                             alreadyHandled = TRUE;
  516.                         }
  517.                     }    
  518.                 }
  519.             }
  520.             break;
  521.             
  522.         case mouseDown:
  523.             /* If it's a mouseDown in our disabled editText item, ignore it. */
  524.             if (!GetCtlValue(CITEMH(d, DJ_QUANTIZE))) {
  525.                 mouseLoc = theEvent->where;
  526.                 GlobalToLocal(&mouseLoc);
  527.                 GetDItem(d, DJ_Q_COLORS, &itemType, &gHandleSink, &itemRect);
  528.                 if (PtInRect(mouseLoc, &itemRect))
  529.                     alreadyHandled = TRUE;
  530.             }
  531.             break;
  532.     }
  533.  
  534.     /* If we are using the NEW dialog manager, we are supposed to call the standard filter
  535.      * proc if we did not handle the event.
  536.      */
  537.     if (alreadyHandled) {
  538.         theEvent->what = nullEvent;
  539.         return FALSE;        /* tricks the dialog manager into handling a null event */
  540.     }
  541.     
  542.     if (gNewDialogMgr) {
  543.         ModalFilterProcPtr    theModalProc;
  544.                 
  545.         if (GetStdFilterProc(&theModalProc) == noErr)
  546.             return theModalProc(d, theEvent, item);
  547.     }
  548.     
  549.     return FALSE;
  550. }
  551.  
  552.  
  553. /* This routine diaplays and handles the dialog for jpeg files.  It handles all of the dialog
  554.  * stuff and returns data in the struct dlog_info.
  555.  */
  556. GLOBAL short
  557. display_djpeg_dialog (FSSpec infile, djpeg_dlog_data *dlog_info)
  558. {
  559.     DialogPtr        d;
  560.     Str255            itext;
  561.     short            num;
  562.     short            item;
  563.     short            itemt;
  564.     Handle            itemh;
  565.     ControlHandle    itemch;
  566.     Rect            itemr;
  567.     Boolean            userchange_outfile=FALSE;
  568.     Boolean            userwants_quantize=FALSE;
  569.     Boolean            need_replace_check=TRUE;
  570.     Str63            tempstr;
  571.     Str63            stdoutfile;
  572.     FSSpec            outspec;
  573.     StandardFileReply    reply;
  574.  
  575.     /* Supposed to call this with system 7 and apple events */
  576.     if (gAppleEvents)
  577.         if (AEInteractWithUser(kAEDefaultTimeout,NULL,NULL)) {
  578.             SysBeep(0L);
  579.             return;
  580.         }
  581.  
  582.     dlog_info->format = DEFAULT_FMT;
  583.  
  584.     if (!gNewDialogMgr)
  585.         CenterDialog(DJPEG_DLOG_ID, NULL);
  586.     d = GetNewDialog(DJPEG_DLOG_ID, NULL, (WindowPtr)-1);
  587.     SetPort(d);
  588.  
  589.     /* If we are using the NEW dialog manager, it will handle the OK and CANCEL keyboard
  590.      * equivalents.  It will also border the OK button for us.  We don't wan't it to
  591.      * track the cursor since we have a "disabled" editText item.
  592.      */
  593.     if (gNewDialogMgr) {
  594.         SetDialogDefaultItem(d, ok);
  595.         SetDialogCancelItem(d, J_CAN);
  596.         SetDialogTracksCursor(d, FALSE);
  597.         
  598.         GetDItem(d, DJ_OKBORDER, &item, &gHandleSink, &itemr);
  599.         SetDItem(d, DJ_OKBORDER, item, (Handle)NOPRoutine, &itemr);
  600.     } else {
  601.         GetDItem(d, DJ_OKBORDER, &item, &gHandleSink, &itemr);
  602.         SetDItem(d, DJ_OKBORDER, item, (Handle)BorderDefault, &itemr);
  603.     }
  604.         
  605.     /* set up the user item that dims the # of colors when quantize is off */
  606.     GetDItem(d, DJ_DIMCOLORS, &item, &gHandleSink, &itemr);
  607.     SetDItem(d, DJ_DIMCOLORS, item, (Handle)DimColors, &itemr);
  608.  
  609.     /* Fill in the dialog's input file name and generate an appropriate output file name */
  610.     SetIText(ditemh(d, J_INFILE), infile.name);
  611.     fix_name(stdoutfile, infile.name, dlog_info->format);
  612.     SetIText(ditemh(d, J_OUTFILE), stdoutfile);
  613.     outspec = infile;
  614.     COPY(outspec.name, stdoutfile);
  615.  
  616.     /* Set the radio buttons for the default output format */
  617.     for (item=DJ_GIF;  item <= DJ_TARGA;  item++)
  618.         SetCtlValue(CITEMH(d,item), (item == dlog_info->format));
  619.         
  620. #ifndef GIF_SUPPORTED
  621.     dimItem(d, DJ_GIF);
  622. #endif
  623. #ifndef PPM_SUPPORTED
  624.     dimItem(d, DJ_PPM);
  625. #endif
  626. #ifndef RLE_SUPPORTED
  627.     dimItem(d, DJ_RLE);
  628. #endif
  629. #ifndef TARGA_SUPPORTED
  630.     dimItem(d, DJ_TARGA);
  631. #endif
  632. #ifndef QUANT_1PASS_SUPPORTED
  633.     dimItem(d, DJ_Q_1PASS);
  634. #endif
  635. #ifndef BLOCK_SMOOTHING_SUPPORTED
  636.     dimItem(d, DJ_SMOOTH);
  637. #endif
  638.  
  639.     /* If the output format is GIF, set up quantizing */
  640.     if (dlog_info->format == FMT_GIF) {
  641.         SetCtlValue(CITEMH(d,DJ_QUANTIZE), 1);
  642.         disableItem(d, DJ_QUANTIZE);
  643.         enableItem(d, DJ_Q_COLORS);
  644.         SelIText(d, DJ_Q_COLORS, 0, MAXINT);
  645.         undimItem(d, DJ_Q_NODITHER);
  646. #ifdef QUANT_1PASS_SUPPORTED
  647.         undimItem(d, DJ_Q_1PASS);
  648. #endif
  649. #ifndef QUANT_2PASS_SUPPORTED
  650.         SetCtlValue(CITEMH(d,DJ_Q_1PASS), 1);
  651.         disableItem(d, DJ_Q_1PASS);
  652. #endif
  653.     } else {
  654.         enableItem(d, DJ_QUANTIZE);
  655.         disableItem(d, DJ_Q_COLORS);
  656.         dimItem(d, DJ_Q_NODITHER);
  657.         dimItem(d, DJ_Q_1PASS);
  658.         SelIText(d, DJ_DEBUG, 0, MAXINT);
  659.     }
  660.  
  661.     /* Show the dialog */
  662.     ShowWindow((WindowPtr)d);
  663.     
  664.     /* Main loop for processing the user's dialog interaction */
  665.     for (;;) {
  666.         ModalDialog((ModalFilterProcPtr)djpeg_dialog_filter, &item);
  667.         if (item <= J_CAN)
  668.             break;
  669.         
  670.         itemh = ditemh(d,item);
  671.         itemch = (ControlHandle)itemh;
  672.         switch (item) {
  673.             case J_SETFILE:
  674.                 /* We want to remember if the user has changed the default output file name */
  675.                 /* because, if they have, we can't keep changing it on them if they change  */
  676.                 /* the output file format.  Also, we can't handle an OK ALL any more.       */
  677.                 GetIText(ditemh(d,J_OUTFILE), tempstr);
  678.                 PutFile("\pSelect output file:", tempstr, &reply);
  679.                 if (reply.sfGood) {
  680.                     outspec = reply.sfFile;
  681.                     need_replace_check = FALSE;    
  682.                     SetIText(ditemh(d, J_OUTFILE), outspec.name);
  683.  
  684.                     for (num=0, userchange_outfile=FALSE;
  685.                          !userchange_outfile  &&  (num <= stdoutfile[0]);  num++)
  686.                         if (stdoutfile[num] != outspec.name[num])
  687.                             userchange_outfile = TRUE;
  688.                                         
  689.                     if (userchange_outfile)
  690.                         dimItem(d, J_OK_ALL);
  691.                     else
  692.                         undimItem(d, J_OK_ALL);
  693.                 }
  694.                 break;
  695.  
  696.             case DJ_GIF:
  697.             case DJ_PPM:
  698.             case DJ_RLE:
  699.             case DJ_TARGA:
  700.                 /* Change current format.  Fix radio buttons. */
  701.                 dlog_info->format = item;
  702.                 for (item=DJ_GIF;  item <= DJ_TARGA;  item++)
  703.                     SetCtlValue(CITEMH(d,item), (item == dlog_info->format));
  704.                     
  705.                 /* If they picked GIF, we must quantize (256)! */
  706.                 if (dlog_info->format == FMT_GIF) {
  707.                     SetCtlValue(CITEMH(d,DJ_QUANTIZE), 1);
  708.                     disableItem(d, DJ_QUANTIZE);
  709.                     GetIText(ditemh(d,DJ_Q_COLORS), itext);
  710.                     if (myStringToNum(itext, &num)) {
  711.                         if (num > 256) {
  712.                             SysBeep(1);
  713.                             SetIText(ditemh(d,DJ_Q_COLORS), "\p256");
  714.                         }
  715.                     } else {
  716.                         SysBeep(1);
  717.                         SetIText(ditemh(d,DJ_Q_COLORS), "\p256");
  718.                     }
  719.                     enableItem(d, DJ_Q_COLORS);
  720.                     SelIText(d, DJ_Q_COLORS, 0, MAXINT);
  721.                     GetDItem(d, DJ_Q_COLORS, &itemt, &gHandleSink, &itemr);
  722.                     InvalRect(&itemr);
  723.                     undimItem(d, DJ_Q_NODITHER);
  724. #ifdef QUANT_1PASS_SUPPORTED
  725.                     undimItem(d, DJ_Q_1PASS);
  726. #endif
  727. #ifndef QUANT_2PASS_SUPPORTED
  728.                     SetCtlValue(CITEMH(d,DJ_Q_1PASS), 1);
  729.                     disableItem(d, DJ_Q_1PASS);
  730. #endif
  731.                 } else {
  732.                     /* If they didn't pick GIF, and the only reason that quantization */
  733.                     /* is on is because WE turned it on for him, turn it off again.   */
  734.                     enableItem(d, DJ_QUANTIZE);
  735.                     if (GetCtlValue(CITEMH(d, DJ_QUANTIZE)) && !userwants_quantize) {
  736.                         SetCtlValue(CITEMH(d,DJ_QUANTIZE), 0);
  737.                         disableItem(d, DJ_Q_COLORS);
  738.                         if (((DialogPeek)d)->editField+1 == DJ_Q_COLORS)
  739.                             SelIText(d, DJ_DEBUG, 0, MAXINT);
  740.                         GetDItem(d, DJ_Q_COLORS, &itemt, &gHandleSink, &itemr);
  741.                         InvalRect(&itemr);
  742.                         dimItem(d, DJ_Q_NODITHER);
  743.                         dimItem(d, DJ_Q_1PASS);
  744.                     }
  745.                 }
  746.                 
  747.                 /* If the user picked his own output file name, don't mess it up. */
  748.                 /* Otherwise, change it appropriately for the output file type.   */
  749.                 if (!userchange_outfile) {
  750.                     fix_name(stdoutfile, infile.name, dlog_info->format);
  751.                     COPY(outspec.name, stdoutfile);
  752.                     SetIText(ditemh(d, J_OUTFILE), stdoutfile);
  753.                 }
  754.                 break;
  755.  
  756.             case DJ_QUANTIZE:
  757.                 if (GetCtlValue(itemch)) {
  758.                     /* Can't turn off quantize if GIF! */
  759.                     if (dlog_info->format == FMT_GIF)
  760.                         /* this can't be hit because cntrl is disabled */
  761.                         SysBeep(1);
  762.                     else {
  763.                         SetCtlValue(itemch, 0);
  764.                         disableItem(d, DJ_Q_COLORS);
  765.                         if (((DialogPeek)d)->editField+1 == DJ_Q_COLORS)
  766.                             SelIText(d, DJ_DEBUG, 0, MAXINT);
  767.                         GetDItem(d, DJ_Q_COLORS, &itemt, &gHandleSink, &itemr);
  768.                         InvalRect(&itemr);
  769.                         dimItem(d, DJ_Q_NODITHER);
  770.                         dimItem(d, DJ_Q_1PASS);
  771.                         userwants_quantize = FALSE;
  772.                     }
  773.                 } else {
  774.                     SetCtlValue(itemch, 1);
  775.                     GetIText(ditemh(d,DJ_Q_COLORS), itext);
  776.                     if (!myStringToNum(itext, &num)) {
  777.                         SysBeep(1);
  778.                         SetIText(ditemh(d,DJ_Q_COLORS), "\p256");
  779.                     }
  780.                     enableItem(d, DJ_Q_COLORS);
  781.                     SelIText(d, DJ_Q_COLORS, 0, MAXINT);
  782.                     GetDItem(d, DJ_Q_COLORS, &itemt, &gHandleSink, &itemr);
  783.                     InvalRect(&itemr);
  784.                     undimItem(d, DJ_Q_NODITHER);
  785. #ifdef QUANT_1PASS_SUPPORTED
  786.                     undimItem(d, DJ_Q_1PASS);
  787. #endif
  788. #ifndef QUANT_2PASS_SUPPORTED
  789.                     SetCtlValue(CITEMH(d,DJ_Q_1PASS), 1);
  790.                     disableItem(d, DJ_Q_1PASS);
  791. #endif
  792.                     userwants_quantize = TRUE;
  793.                 }
  794.                 break;
  795.  
  796.             case DJ_Q_COLORS:
  797.                 GetIText(itemh, itext);
  798.                 /* If invalid number, use 256 */
  799.                 if (!myStringToNum(itext, &num)) {
  800.                     SysBeep(1);
  801.                     SetIText(itemh, "\p256");
  802.                 } else
  803.                     /* GIF can't be greater than 256! */
  804.                     if (dlog_info->format == FMT_GIF  &&  num > 256) {
  805.                         SysBeep(1);
  806.                         SetIText(itemh, "\p256");
  807.                     }
  808.                 break;
  809.  
  810.             case DJ_Q_1PASS:
  811.             case DJ_Q_NODITHER:
  812.                 SetCtlValue(itemch, 1-GetCtlValue(itemch));
  813.                 userwants_quantize = TRUE;
  814.                 break;
  815.                 
  816.             case DJ_GRAY:
  817.             case DJ_SMOOTH:
  818.                 SetCtlValue(itemch, 1-GetCtlValue(itemch));
  819.                 break;
  820.                 
  821.             case DJ_DEBUG:
  822.                 GetIText(itemh, itext);
  823.                 if (!myStringToNum(itext, &num)) {
  824.                     SysBeep(1);
  825.                     SetIText(itemh, "\p0");
  826.                 }
  827.                 break;
  828.         }
  829.     }
  830.         
  831.     /* If the user hit OK or OK_ALL, copy the dialog info into static vars.  (Static */
  832.     /* because they will be here on the next file if OK_ALL was hit.)                */
  833.     if (item != J_CAN) {
  834.         dlog_info->smoothing = GetCtlValue(CITEMH(d,DJ_SMOOTH));
  835.  
  836.         dlog_info->grayscale = GetCtlValue(CITEMH(d,DJ_GRAY));
  837.  
  838.         dlog_info->quantize = GetCtlValue(CITEMH(d,DJ_QUANTIZE));
  839.  
  840.         GetIText(ditemh(d,DJ_Q_COLORS), itext);
  841.         myStringToNum(itext, &(dlog_info->colors));
  842.  
  843.         dlog_info->onepass = GetCtlValue(CITEMH(d,DJ_Q_1PASS));
  844.  
  845.         dlog_info->nodither = GetCtlValue(CITEMH(d,DJ_Q_NODITHER));
  846.         
  847.         GetIText(ditemh(d,DJ_DEBUG), itext);
  848.         myStringToNum(itext, &(dlog_info->debug));
  849.         
  850.         dlog_info->outfile = outspec;
  851.         dlog_info->replace_ok = !need_replace_check;
  852.     }
  853.     
  854.     DisposDialog(d);
  855.     InitCursor();
  856.     
  857.     return item;
  858. }
  859.  
  860.  
  861. /* This is the dialog filter for the cjpeg dialog.  It does a bunch of stuff that a filter
  862.  * proc needs to do.  It also takes care of numeric entry, etc.
  863.  */
  864. METHODDEF pascal Boolean
  865. cjpeg_dialog_filter (DialogPtr d, EventRecord *theEvent, short *item)
  866. {
  867.     short    itemType;
  868.     Handle    itemHandle;
  869.     Rect    itemRect;
  870.     Point    mouseLoc;
  871.     char    theKey;
  872.     Boolean    command;
  873.     Boolean    alreadyHandled=FALSE;
  874.     
  875.     SetPort(d);
  876.     
  877.     /* If the OLD dialog manager, we have to track the cursor ourself.  Otherwise, the new
  878.      * dialog manager will do this for us.
  879.      */
  880.     if (!gNewDialogMgr) {
  881.         GetMouse(&mouseLoc);
  882.         GetDItem(d, CJ_QUALITY, &itemType, &gHandleSink, &itemRect);
  883.         if (PtInRect(mouseLoc, &itemRect))
  884.             SetCursor(*GetCursor(1));
  885.         else {
  886.             GetDItem(d, CJ_DEBUG, &itemType, &gHandleSink, &itemRect);
  887.             if (PtInRect(mouseLoc, &itemRect))
  888.                 SetCursor(*GetCursor(1));
  889.             else
  890.                 SetCursor(&arrow);
  891.         }
  892.     }
  893.     
  894.     if (ReturnEnterEscape(d, theEvent, item))
  895.         return TRUE;
  896.  
  897.     switch (theEvent->what) {
  898.         case keyDown:
  899.         case autoKey:
  900.             theKey = theEvent->message & charCodeMask;
  901.             command = ((theEvent->modifiers & cmdKey) != 0);
  902.             
  903.             if (!command  &&  !IsEditKey(theKey, command))
  904.                 switch (((DialogPeek)d)->editField+1) {
  905.                     /* CJ_QUALITY and CJ_DEBUG can only contain numbers */
  906.                     case CJ_QUALITY:
  907.                     case CJ_DEBUG:
  908.                         if ((theKey < '0') || (theKey > '9')) {
  909.                             SysBeep(1);
  910.                             alreadyHandled = TRUE;
  911.                         }
  912.                         break;
  913.                 }
  914.  
  915.             /* Take case of field size limits on the edit text fields */
  916.             if (!alreadyHandled) {
  917.                 short    max_chars;
  918.                 short    selection;
  919.                 long    scraplen;
  920.                 long    offset;
  921.                 Str63    theText;
  922.                 
  923.                 switch (((DialogPeek)d)->editField+1) {
  924.                     case CJ_QUALITY:
  925.                         max_chars = 3;
  926.                         break;
  927.                     case CJ_DEBUG:
  928.                         max_chars = 1;
  929.                         break;
  930.                 }
  931.                     
  932.                 selection = HasSelectionRange((DialogPeek)d);
  933.                 
  934.                 GetIText(ditemh(d, ((DialogPeek)d)->editField+1), theText);
  935.                 
  936.                 if (IsEditKey(theKey, command)) {
  937.                     if ((theKey == 'V') || (theKey == 'v')) {
  938.                         scraplen = GetScrap(NULL, 'TEXT', &offset);
  939.                         if (theText[0] + scraplen - selection > max_chars) {
  940.                             SysBeep(1);
  941.                             alreadyHandled = TRUE;
  942.                         }
  943.                     }
  944.                 } else {
  945.                     if (theText[0] + 1 - selection > max_chars) {
  946.                         SysBeep(1);
  947.                         alreadyHandled = TRUE;
  948.                     }
  949.                 }    
  950.             }
  951.             break;
  952.     }
  953.  
  954.     /* If we have already handled the event, pass back a nullEvent to keep ModalDialog from
  955.      * returning.  Otherwise, if we are using the NEW dialog manager, we need to call the
  956.      * standard filter proc.
  957.      */
  958.     if (alreadyHandled) {
  959.         theEvent->what = nullEvent;
  960.         return FALSE;        /* tricks the dialog manager into handling a null event */
  961.     }
  962.     
  963.     if (gNewDialogMgr) {
  964.         ModalFilterProcPtr    theModalProc;
  965.                 
  966.         if (GetStdFilterProc(&theModalProc) == noErr)
  967.             return theModalProc(d, theEvent, item);
  968.     }
  969.     
  970.     return FALSE;
  971. }
  972.  
  973.  
  974. /* This is the routine that will display the dialog for the non-jpeg files.  It returns data
  975.  * to the caller in the dlog_info struct.
  976.  */
  977. GLOBAL short
  978. display_cjpeg_dialog (FSSpec infile, cjpeg_dlog_data *dlog_info)
  979. {
  980.     short            item;
  981.     DialogPtr        d;
  982.     Str255            itext;
  983.     short            num;
  984.     Handle            itemh;
  985.     ControlHandle    itemch;
  986.     Rect            itemr;
  987.     Str63            tempstr;
  988.     Str63            stdoutfile;
  989.     Boolean            need_replace_check=TRUE;
  990.     Boolean            userchange_outfile;
  991.     FSSpec            outspec;
  992.     StandardFileReply    reply;
  993.     
  994.     /* Supposed to call this with system 7 and apple events */
  995.     if (gAppleEvents)
  996.         if (AEInteractWithUser(kAEDefaultTimeout,NULL,NULL)) {
  997.             SysBeep(0L);
  998.             return;
  999.         }
  1000.  
  1001.     if (!gNewDialogMgr)
  1002.         CenterDialog(CJPEG_DLOG_ID, NULL);
  1003.     d = GetNewDialog(CJPEG_DLOG_ID, NULL, (WindowPtr)-1);
  1004.     SetPort(d);
  1005.  
  1006.     /* If we are using the NEW dialog manager, it can handle the OK and CANCEL buttons.
  1007.      * It will also track our cursor for us.
  1008.      */
  1009.     if (gNewDialogMgr) {
  1010.         SetDialogDefaultItem(d, ok);
  1011.         SetDialogCancelItem(d, J_CAN);
  1012.         SetDialogTracksCursor(d, TRUE);
  1013.         
  1014.         GetDItem(d, CJ_OKBORDER, &item, (Handle *)&gHandleSink, &itemr);
  1015.         SetDItem(d, CJ_OKBORDER, item, (Handle)NOPRoutine, &itemr);
  1016.     } else {
  1017.         GetDItem(d, CJ_OKBORDER, &item, (Handle *)&gHandleSink, &itemr);
  1018.         SetDItem(d, CJ_OKBORDER, item, (Handle)BorderDefault, &itemr);
  1019.     }
  1020.  
  1021.     /* If optimization not compiled in, disable the item */    
  1022. #ifndef ENTROPY_OPT_SUPPORTED
  1023.     dimItem(d, CJ_OPT);
  1024. #endif
  1025. #ifndef C_ARITH_CODING_SUPPORTED
  1026.     dimItem(d, CJ_ARITH);
  1027. #endif
  1028. #ifndef TARGA_SUPPORTED
  1029.     dimItem(d, CJ_TARGA);
  1030. #endif
  1031. #ifndef C_MULTISCAN_FILES_SUPPORTED
  1032.     dimItem(d, CJ_NONINTER);
  1033. #endif
  1034.  
  1035.     /* Fill in the dialog's input file name and generate an appropriate output file name */
  1036.     SetIText(ditemh(d, J_INFILE), infile.name);
  1037.     fix_name(stdoutfile, infile.name, FMT_JPEG);
  1038.     SetIText(ditemh(d, J_OUTFILE), stdoutfile);
  1039.     outspec = infile;
  1040.     COPY(outspec.name, stdoutfile);
  1041.  
  1042.     ShowWindow((WindowPtr)d);
  1043.     
  1044.     for (;;) {
  1045.         ModalDialog((ModalFilterProcPtr)cjpeg_dialog_filter, &item);
  1046.         if (item <= J_CAN)
  1047.             break;
  1048.         
  1049.         itemh = ditemh(d,item);
  1050.         itemch = (ControlHandle)itemh;
  1051.         switch (item) {
  1052.             case J_SETFILE:
  1053.                 /* We want to remember if the user has changed the default output file name */
  1054.                 /* because, if they have, we can't keep changing it on them if they change  */
  1055.                 /* the output file format.  Also, we can't handle an OK ALL any more.       */
  1056.                 GetIText(ditemh(d,J_OUTFILE), tempstr);
  1057.                 PutFile("\pSelect output file:", tempstr, &reply);
  1058.                 if (reply.sfGood) {
  1059.                     outspec = reply.sfFile;
  1060.                     need_replace_check = FALSE;
  1061.                     SetIText(ditemh(d, J_OUTFILE), outspec.name);
  1062.                     
  1063.                     for (num=0, userchange_outfile=FALSE;
  1064.                          !userchange_outfile  &&  (num <= stdoutfile[0]);  num++)
  1065.                         if (stdoutfile[num] != outspec.name[num])
  1066.                             userchange_outfile = TRUE;
  1067.                                         
  1068.                     if (userchange_outfile)
  1069.                         dimItem(d, J_OK_ALL);
  1070.                     else
  1071.                         undimItem(d, J_OK_ALL);
  1072.                 }
  1073.                 break;
  1074.  
  1075.             case CJ_QUALITY:
  1076.                 GetIText(itemh, itext);
  1077.                 if (myStringToNum(itext, &num)) {
  1078.                     if (num > 100) {
  1079.                         SysBeep(1);
  1080.                         SetIText(itemh, "\p100");
  1081.                     }
  1082.                 } else {
  1083.                     SysBeep(1);
  1084.                     SetIText(itemh, "\p75");
  1085.                 }
  1086.                 break;
  1087.                 
  1088.             case CJ_OPT:
  1089.             case CJ_GRAY:
  1090.             case CJ_TARGA:
  1091.             case CJ_NONINTER:
  1092.             case CJ_ARITH:
  1093.                 SetCtlValue(itemch, 1-GetCtlValue(itemch));
  1094.                 break;
  1095.  
  1096.             case CJ_DEBUG:
  1097.                 GetIText(itemh, itext);
  1098.                 if (!myStringToNum(itext, &num)) {
  1099.                     SysBeep(1);
  1100.                     SetIText(itemh, "\p0");
  1101.                 }
  1102.                 break;
  1103.         }
  1104.     }
  1105.         
  1106.     /* Store dialog info in temp vars */
  1107.     if (item != J_CAN) {
  1108.         GetIText(ditemh(d,CJ_QUALITY), itext);
  1109.         myStringToNum(itext, &dlog_info->quality);
  1110.  
  1111.         dlog_info->grayscale = GetCtlValue(CITEMH(d,CJ_GRAY));
  1112.  
  1113.         dlog_info->targa = GetCtlValue(CITEMH(d,CJ_TARGA));
  1114.  
  1115.         dlog_info->optimize = GetCtlValue(CITEMH(d,CJ_OPT));
  1116.         
  1117.         dlog_info->arithmetic = GetCtlValue(CITEMH(d,CJ_ARITH));
  1118.         
  1119.         dlog_info->nointerleave = GetCtlValue(CITEMH(d, CJ_NONINTER));
  1120.         
  1121.         GetIText(ditemh(d,CJ_DEBUG), itext);
  1122.         myStringToNum(itext, &dlog_info->debug);
  1123.  
  1124.         dlog_info->outfile = outspec;
  1125.         dlog_info->replace_ok = !need_replace_check;
  1126.     }
  1127.     
  1128.     DisposDialog(d);
  1129.     InitCursor();
  1130.     
  1131.     return item;
  1132. }
  1133.  
  1134.  
  1135. /* set the prefs to their default values */
  1136. LOCAL PrefHandle
  1137. default_prefs ()
  1138. {
  1139.     PrefHandle    phand;
  1140.     
  1141.     phand = (PrefHandle)NewHandle(sizeof(prefs_data));
  1142.  
  1143.     (**phand).pref_version = PREF_VERSION;
  1144.     
  1145.     (**phand).progressLoc.h = 20;
  1146.     (**phand).progressLoc.v = 40;
  1147.     
  1148.     (**phand).jpeg_type = 'JPEG';
  1149.     (**phand).jpeg_creator = appSignature;
  1150.     (**phand).gif_type = 'GIFf';
  1151.     (**phand).gif_creator = appSignature;
  1152.     (**phand).ppm_type = 'PPM ';
  1153.     (**phand).ppm_creator = appSignature;
  1154.     (**phand).targa_type = 'TARG';
  1155.     (**phand).targa_creator = appSignature;
  1156.     (**phand).rle_type = 'RLE ';
  1157.     (**phand).rle_creator = appSignature;
  1158.  
  1159.     (**phand).overwrite = FALSE;
  1160.     (**phand).show_all = FALSE;
  1161.     
  1162.     MoveHHi((Handle)phand);
  1163.     HLock((Handle)phand);
  1164.  
  1165.     return phand;
  1166. }
  1167.  
  1168.  
  1169. /* This routine will read the prefs file.  If a prefs file does not exist, a default prefs file
  1170.  * is created.
  1171.  */
  1172. GLOBAL void
  1173. read_preference_file ()
  1174. {
  1175.     OSErr    err;
  1176.     short    prefsVRefNum;
  1177.     long    prefsDirID;
  1178.     FSSpec    prefsFSSpec;
  1179.     short    prefFile;
  1180.  
  1181.     /* Think C has glue for FindFolder for system 6.  So this should be OK as long as
  1182.      * the user hasn't set the "SystemSevenOrLater" define to 1.  If so, it's his lunch
  1183.      * when this puppy crashes under 6.
  1184.      */
  1185.     err = FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder,
  1186.                         &prefsVRefNum, &prefsDirID);
  1187.     if (err != noErr) {
  1188.         Error(err, "\pError finding preferences folder", "\pUsing default prefs");
  1189.         gPrefs = default_prefs();
  1190.         return;
  1191.     }
  1192.  
  1193.     /* make a file spec for the prefs file */
  1194.     err = xFSMakeFSSpec(prefsVRefNum, prefsDirID, "\pJPEG Convert Prefs", &prefsFSSpec);
  1195.     if (err == fnfErr) {
  1196.         /* prefs file doesn't already exist, so create it */
  1197.         err = xFSpCreateResFile(&prefsFSSpec, appSignature, 'PREF', smSystemScript);
  1198.         if (err != noErr) {
  1199.             Error(err, "\pError creating a new preferences file", "\pContinuing without one");
  1200.             gPrefs = default_prefs();
  1201.             return;
  1202.         }
  1203.     }
  1204.     
  1205.     /* open the prefs file */
  1206.     prefFile = xFSpOpenResFile(&prefsFSSpec, fsRdWrPerm);
  1207.     err = ResError();
  1208.     if (err != noErr) {
  1209.         Error(err, "\pCouldn't open prefs file.", "\pPrefs will not be saved.");
  1210.         gPrefs = default_prefs();
  1211.         return;
  1212.     }
  1213.     
  1214.     /* read the resource */
  1215.     gPrefs = (PrefHandle)GetResource('PREF', 1);
  1216.     if (gPrefs == NULL) {
  1217.         gPrefs = default_prefs();
  1218.         AddResource((Handle)gPrefs, 'PREF', 1, NULL);
  1219.         err = ResError();
  1220.         if (err != noErr) {
  1221.             Error(err, "\pCouldn't create prefs resource", "\pPrefs will not be saved.");
  1222.             return;
  1223.         }
  1224.     } else {
  1225.         MoveHHi((Handle)gPrefs);
  1226.         HLock((Handle)gPrefs);
  1227.     }
  1228.     
  1229.     /* Here is where I will compare the prefs version number and update if needed */
  1230. }
  1231.  
  1232.  
  1233. /* This is the dialog filter for the prefs dialog.  It does a bunch of stuff that a filter
  1234.  * proc needs to do.  It also takes care of limited fields, etc.
  1235.  */
  1236. METHODDEF pascal Boolean
  1237. prefs_dialog_filter (DialogPtr d, EventRecord *theEvent, short *item)
  1238. {
  1239.     short    itemType;
  1240.     Handle    itemHandle;
  1241.     Rect    itemRect;
  1242.     Point    mouseLoc;
  1243.     char    theKey;
  1244.     Boolean    command;
  1245.     Boolean    alreadyHandled=FALSE;
  1246.     
  1247.     SetPort(d);
  1248.     
  1249.     /* If the OLD dialog manager, we have to track the cursor ourself.  Otherwise, the new
  1250.      * dialog manager will do this for us.
  1251.      */
  1252.     if (!gNewDialogMgr) {
  1253.         GetMouse(&mouseLoc);
  1254.         GetDItem(d, kPjpegT, &itemType, &gHandleSink, &itemRect);
  1255.         if (PtInRect(mouseLoc, &itemRect))
  1256.             SetCursor(*GetCursor(1));
  1257.         else {
  1258.             GetDItem(d, kPjpegC, &itemType, &gHandleSink, &itemRect);
  1259.             if (PtInRect(mouseLoc, &itemRect))
  1260.                 SetCursor(*GetCursor(1));
  1261.             else {
  1262.                 GetDItem(d, kPgifT, &itemType, &gHandleSink, &itemRect);
  1263.                 if (PtInRect(mouseLoc, &itemRect))
  1264.                     SetCursor(*GetCursor(1));
  1265.                 else {
  1266.                     GetDItem(d, kPgifC, &itemType, &gHandleSink, &itemRect);
  1267.                     if (PtInRect(mouseLoc, &itemRect))
  1268.                         SetCursor(*GetCursor(1));
  1269.                     else {
  1270.                         GetDItem(d, kPppmT, &itemType, &gHandleSink, &itemRect);
  1271.                         if (PtInRect(mouseLoc, &itemRect))
  1272.                             SetCursor(*GetCursor(1));
  1273.                         else {
  1274.                             GetDItem(d, kPppmC, &itemType, &gHandleSink, &itemRect);
  1275.                             if (PtInRect(mouseLoc, &itemRect))
  1276.                                 SetCursor(*GetCursor(1));
  1277.                             else {
  1278.                                 GetDItem(d, kPtargaT, &itemType, &gHandleSink, &itemRect);
  1279.                                 if (PtInRect(mouseLoc, &itemRect))
  1280.                                     SetCursor(*GetCursor(1));
  1281.                                 else {
  1282.                                     GetDItem(d, kPtargaC, &itemType, &gHandleSink, &itemRect);
  1283.                                     if (PtInRect(mouseLoc, &itemRect))
  1284.                                         SetCursor(*GetCursor(1));
  1285.                                     else {
  1286.                                         GetDItem(d, kPrleT, &itemType, &gHandleSink, &itemRect);
  1287.                                         if (PtInRect(mouseLoc, &itemRect))
  1288.                                             SetCursor(*GetCursor(1));
  1289.                                         else {
  1290.                                             GetDItem(d, kPrleC, &itemType, &gHandleSink, &itemRect);
  1291.                                             if (PtInRect(mouseLoc, &itemRect))
  1292.                                                 SetCursor(*GetCursor(1));
  1293.                                             else
  1294.                                                 SetCursor(&arrow);
  1295.                                         }
  1296.                                     }
  1297.                                 }
  1298.                             }
  1299.                         }
  1300.                     }
  1301.                 }
  1302.             }
  1303.         }
  1304.     }
  1305.  
  1306.     if (ReturnEnterEscape(d, theEvent, item))
  1307.         return TRUE;
  1308.     
  1309.     switch (theEvent->what) {
  1310.         short    max_chars;
  1311.         short    selection;
  1312.         long    scraplen;
  1313.         long    offset;
  1314.         Str63    theText;
  1315.  
  1316.         case keyDown:
  1317.         case autoKey:
  1318.             theKey = theEvent->message & charCodeMask;
  1319.             command = ((theEvent->modifiers & cmdKey) != 0);
  1320.             
  1321.             max_chars = 4;
  1322.                 
  1323.             selection = HasSelectionRange((DialogPeek)d);
  1324.             
  1325.             GetIText(ditemh(d, ((DialogPeek)d)->editField+1), theText);
  1326.  
  1327.             if (IsEditKey(theKey, command)) {
  1328.                 if ((theKey == 'V') || (theKey == 'v')) {
  1329.                     scraplen = GetScrap(NULL, 'TEXT', &offset);
  1330.                     if (theText[0] + scraplen - selection > max_chars) {
  1331.                         SysBeep(1);
  1332.                         alreadyHandled = TRUE;
  1333.                     }
  1334.                 }
  1335.             } else {
  1336.                 if (theText[0] + 1 - selection > max_chars) {
  1337.                     SysBeep(1);
  1338.                     alreadyHandled = TRUE;
  1339.                 }
  1340.             }    
  1341.             break;
  1342.     }
  1343.  
  1344.     /* If we have already handled the event, pass back a nullEvent to keep ModalDialog from
  1345.      * returning.  Otherwise, if we are using the NEW dialog manager, we need to call the
  1346.      * standard filter proc.
  1347.      */
  1348.     if (alreadyHandled) {
  1349.         theEvent->what = nullEvent;
  1350.         return FALSE;        /* tricks the dialog manager into handling a null event */
  1351.     }
  1352.     
  1353.     if (gNewDialogMgr) {
  1354.         ModalFilterProcPtr    theModalProc;
  1355.                 
  1356.         if (GetStdFilterProc(&theModalProc) == noErr)
  1357.             return theModalProc(d, theEvent, item);
  1358.     }
  1359.     
  1360.     return FALSE;
  1361. }
  1362.  
  1363.  
  1364. /* This is the routine that will display the dialog for updating the prefs files.  It updates the
  1365.  * global preferences struct and then re-writes the prefs file if necessary.
  1366.  */
  1367. GLOBAL void
  1368. display_prefs_dialog ()
  1369. {
  1370.     short            item;
  1371.     Handle            itemh;
  1372.     ControlHandle    itemch;
  1373.     DialogPtr        d;
  1374.     Rect            itemr;
  1375.     OSType            sigString=appSignature;
  1376.     Str15            appString;
  1377.     Str15            tempString;
  1378.  
  1379.     /* Supposed to call this with system 7 and apple events */
  1380.     if (gAppleEvents)
  1381.         if (AEInteractWithUser(kAEDefaultTimeout,NULL,NULL)) {
  1382.             SysBeep(0L);
  1383.             return;
  1384.         }
  1385.  
  1386.     if (!gNewDialogMgr)
  1387.         CenterDialog(PREFS_DLOG_ID, NULL);
  1388.     d = GetNewDialog(PREFS_DLOG_ID, NULL, (WindowPtr)-1);
  1389.     SetPort(d);
  1390.  
  1391.     /* If we are using the NEW dialog manager, it can handle the OK and CANCEL buttons.
  1392.      * It will also track our cursor for us.
  1393.      */
  1394.     if (gNewDialogMgr) {
  1395.         SetDialogDefaultItem(d, ok);
  1396.         SetDialogCancelItem(d, cancel);
  1397.         SetDialogTracksCursor(d, TRUE);
  1398.         
  1399.         GetDItem(d, kPok_border, &item, (Handle *)&gHandleSink, &itemr);
  1400.         SetDItem(d, kPok_border, item, (Handle)NOPRoutine, &itemr);
  1401.     } else {
  1402.         GetDItem(d, kPok_border, &item, (Handle *)&gHandleSink, &itemr);
  1403.         SetDItem(d, kPok_border, item, (Handle)BorderDefault, &itemr);
  1404.     }
  1405.  
  1406.     /* Initialize the dialog to the current prefs */
  1407.     OSTYPE_TO_STR((**gPrefs).jpeg_type, tempString);
  1408.     SetIText(ditemh(d, kPjpegT), tempString);
  1409.     OSTYPE_TO_STR((**gPrefs).jpeg_creator, tempString);
  1410.     SetIText(ditemh(d, kPjpegC), tempString);
  1411.     OSTYPE_TO_STR((**gPrefs).gif_type, tempString);
  1412.     SetIText(ditemh(d, kPgifT), tempString);
  1413.     OSTYPE_TO_STR((**gPrefs).gif_creator, tempString);
  1414.     SetIText(ditemh(d, kPgifC), tempString);
  1415.     OSTYPE_TO_STR((**gPrefs).ppm_type, tempString);
  1416.     SetIText(ditemh(d, kPppmT), tempString);
  1417.     OSTYPE_TO_STR((**gPrefs).ppm_creator, tempString);
  1418.     SetIText(ditemh(d, kPppmC), tempString);
  1419.     OSTYPE_TO_STR((**gPrefs).targa_type, tempString);
  1420.     SetIText(ditemh(d, kPtargaT), tempString);
  1421.     OSTYPE_TO_STR((**gPrefs).targa_creator, tempString);
  1422.     SetIText(ditemh(d, kPtargaC), tempString);
  1423.     OSTYPE_TO_STR((**gPrefs).rle_type, tempString);
  1424.     SetIText(ditemh(d, kPrleT), tempString);
  1425.     OSTYPE_TO_STR((**gPrefs).rle_creator, tempString);
  1426.     SetIText(ditemh(d, kPrleC), tempString);
  1427.     SetCtlValue(CITEMH(d,kPoverwrite), (**gPrefs).overwrite);
  1428.     SetCtlValue(CITEMH(d,kPalltypes), (**gPrefs).show_all);
  1429.  
  1430.     SelIText(d, kPjpegT, 0, MAXINT);
  1431.  
  1432.     ShowWindow((WindowPtr)d);
  1433.     
  1434.     for (;;) {
  1435.         ModalDialog((ModalFilterProcPtr)prefs_dialog_filter, &item);
  1436.         if (item <= cancel)
  1437.             break;
  1438.         
  1439.         itemh = ditemh(d,item);
  1440.         itemch = (ControlHandle)itemh;
  1441.         switch (item) {
  1442.             case kPdefault:
  1443.                 OSTYPE_TO_STR(sigString, appString);
  1444.                 SetIText(ditemh(d, kPjpegT), "\pJPEG");
  1445.                 SetIText(ditemh(d, kPjpegC), appString);
  1446.                 SetIText(ditemh(d, kPgifT), "\pGIFf");
  1447.                 SetIText(ditemh(d, kPgifC), appString);
  1448.                 SetIText(ditemh(d, kPppmT), "\pPPM ");
  1449.                 SetIText(ditemh(d, kPppmC), appString);
  1450.                 SetIText(ditemh(d, kPtargaT), "\pTARG");
  1451.                 SetIText(ditemh(d, kPtargaC), appString);
  1452.                 SetIText(ditemh(d, kPrleT), "\pRLE ");
  1453.                 SetIText(ditemh(d, kPrleC), appString);
  1454.                 SetCtlValue(CITEMH(d,kPoverwrite), FALSE);
  1455.                 SetCtlValue(CITEMH(d,kPalltypes), FALSE);
  1456.                 break;
  1457.  
  1458.             case kPoverwrite:
  1459.             case kPalltypes:
  1460.                 SetCtlValue(itemch, 1-GetCtlValue(itemch));
  1461.                 break;
  1462.         }
  1463.     }
  1464.     
  1465.     if (item == ok) {
  1466.         GetIText(ditemh(d,kPjpegT), tempString);  PAD(tempString, ' ', 4);
  1467.         STR_TO_OSTYPE(tempString, (**gPrefs).jpeg_type);        
  1468.         GetIText(ditemh(d,kPjpegC), tempString);  PAD(tempString, ' ', 4);
  1469.         STR_TO_OSTYPE(tempString, (**gPrefs).jpeg_creator);
  1470.  
  1471.         GetIText(ditemh(d,kPgifT), tempString);  PAD(tempString, ' ', 4);
  1472.         STR_TO_OSTYPE(tempString, (**gPrefs).gif_type);
  1473.         GetIText(ditemh(d,kPgifC), tempString);  PAD(tempString, ' ', 4);
  1474.         STR_TO_OSTYPE(tempString, (**gPrefs).gif_creator);
  1475.  
  1476.         GetIText(ditemh(d,kPppmT), tempString);  PAD(tempString, ' ', 4);
  1477.         STR_TO_OSTYPE(tempString, (**gPrefs).ppm_type);
  1478.         GetIText(ditemh(d,kPppmC), tempString);  PAD(tempString, ' ', 4);
  1479.         STR_TO_OSTYPE(tempString, (**gPrefs).ppm_creator);
  1480.  
  1481.         GetIText(ditemh(d,kPtargaT), tempString);  PAD(tempString, ' ', 4);
  1482.         STR_TO_OSTYPE(tempString, (**gPrefs).targa_type);
  1483.         GetIText(ditemh(d,kPtargaC), tempString);  PAD(tempString, ' ', 4);
  1484.         STR_TO_OSTYPE(tempString, (**gPrefs).targa_creator);
  1485.  
  1486.         GetIText(ditemh(d,kPrleT), tempString);  PAD(tempString, ' ', 4);
  1487.         STR_TO_OSTYPE(tempString, (**gPrefs).rle_type);
  1488.         GetIText(ditemh(d,kPrleC), tempString);  PAD(tempString, ' ', 4);
  1489.         STR_TO_OSTYPE(tempString, (**gPrefs).rle_creator);
  1490.  
  1491.         (**gPrefs).overwrite = GetCtlValue(CITEMH(d,kPoverwrite));
  1492.         (**gPrefs).show_all = GetCtlValue(CITEMH(d,kPalltypes));
  1493.         
  1494.         ChangedResource((Handle)gPrefs);
  1495.     }
  1496.  
  1497.     DisposDialog(d);
  1498.     InitCursor();
  1499. }